package com.koron.operation.classes.form.excel;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.operation.classes.form.bean.dto.ClassesFormDTO;
import com.koron.operation.classes.form.bean.dto.ClassesFormRankDTO;
import com.koron.operation.classes.form.bean.dto.ClassesFormRowDTO;
import com.koron.operation.classes.form.bean.dto.ClassesFormShiftDTO;
import com.koron.operation.classes.form.bean.po.ClassesFormRank;
import com.koron.operation.classes.form.bean.po.ClassesFormUser;
import com.koron.operation.classes.form.service.ClassesFormService;
import com.koron.operation.classes.info.bean.dto.ClassesClassifyDTO;
import com.koron.operation.classes.info.bean.po.ClassesClassifyItem;
import com.koron.operation.classes.info.service.ClassesClassifyService;
import lombok.RequiredArgsConstructor;
import org.koron.ebs.mybatis.SessionFactory;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author jzp
 * @since 2023/6/19
 */
@RequiredArgsConstructor
public class ClassesFormListener extends AnalysisEventListener<Map<Integer, String>> {

    private static final int BATCH_COUNT = 5;
    private final String id;
    private final ClassesFormService classesFormService;
    private final ClassesClassifyService classesClassifyService;

    private final List<Map<Integer, String>> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private Map<String, ClassesFormRankDTO> rankMap;
    private Map<String, ClassesFormUser> userMap;
    private Map<String, ClassesFormUser> userPinyinMap;
    private Map<String, ClassesClassifyItem> classesItemMap;
    private ClassesFormDTO classesFormDTO;

    private String getCurrDs() {
        return ThreadLocalContext.get().getCurrDs();
    }

    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        cachedDataList.add(data);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        ExcelCoordinateUtil.ClassesFormCell formCell = ExcelCoordinateUtil.ClassesFormCell.SHIFT_ROW;
        try (SessionFactory factory = new SessionFactory()) {
            factory.setDbEnv(getCurrDs());
            // 查询排班表基本数据
            classesFormDTO = classesFormService.getDtoById(factory, id);
            int month = Integer.parseInt(StrUtil.strip(cachedDataList.get(ExcelCoordinateUtil.ClassesFormCell.MONTH.getRowIndex()).get(ExcelCoordinateUtil.ClassesFormCell.MONTH.getCollIndex()), "月"));
            int year = Integer.parseInt(cachedDataList.get(ExcelCoordinateUtil.ClassesFormCell.YEAR.getRowIndex()).get(ExcelCoordinateUtil.ClassesFormCell.YEAR.getCollIndex()));
            Date shiftTime = classesFormDTO.getShiftTime();
            DateTime parse = DateUtil.parse(year + "-" + month, "yyyy-MM");
            Assert.isTrue(Objects.equals(shiftTime, parse), "excel中的排班年月和数据不一致");
            // 岗位map rankName: rankDTO
            List<ClassesFormRankDTO> classesFormRankDTOList = classesFormService.getUserListByOrgId(factory, classesFormDTO.getDeptId());
            rankMap = classesFormRankDTOList.stream().collect(Collectors.toMap(ClassesFormRank::getRankName, e -> e));

            // username: userId
            userMap = classesFormRankDTOList.stream()
                    .map(ClassesFormRankDTO::getUsers)
                    .flatMap(Collection::stream)
                    .collect(Collectors.toMap(ClassesFormUser::getUserName, e -> e, (o1,o2) -> o1));

            // username: userId
            userPinyinMap = classesFormRankDTOList.stream()
                    .map(ClassesFormRankDTO::getUsers)
                    .flatMap(Collection::stream)
                    .collect(Collectors.toMap(ClassesFormUser::getUserPinyin, e -> e, (o1,o2) -> o1));

            // 查询对应的排班方案
            ClassesClassifyDTO classesClassifyDTO = classesClassifyService.getDtoById(factory, classesFormDTO.getClassesId());
            List<ClassesClassifyItem> items = classesClassifyDTO.getItems();
            // classesName: classes
            classesItemMap = items.stream().collect(Collectors.toMap(ClassesClassifyItem::getName, e -> e));


            // excel数据
            // 清除数据
            if (classesFormDTO.getRowList() != null) {
                classesFormDTO.getRowList().clear();
            }
            ClassesFormRowDTO classesFormRowDto = null;
            // 本月几天
            ExcelCoordinateUtil.ClassesFormCell day = ExcelCoordinateUtil.ClassesFormCell.DAY;
            int days = Integer.parseInt(cachedDataList.get(day.getRowIndex()).get(day.getCollIndex()));
            for (Map<Integer, String> map : cachedDataList.subList(formCell.getRowIndex(), cachedDataList.size())) {
                String firstCol = map.get(0);
                if (StrUtil.isBlank(firstCol)) {
                    break;
                }
                if (firstCol.contains("\n")) {
                    String[] split = firstCol.split("\n");
                    if (split.length == 1) {
                        firstCol = split[0];
                    } else {
                        firstCol = split[1];
                    }
                }
                if (userMap.containsKey(firstCol)) {
                    Assert.notNull(classesFormRowDto, "未找到该用户" + firstCol + "所属岗位");
                    ClassesFormRowDTO rowDTO = BeanUtil.toBean(classesFormRowDto, ClassesFormRowDTO.class);
                    ClassesFormUser classesFormUser = userMap.get(firstCol);
                    rowDTO.setUserId(classesFormUser.getUserId());
                    rowDTO.setUserName(classesFormUser.getUserName());
                    rowDTO.setUserPinyin(classesFormUser.getUserPinyin());
                    classesFormDTO.getRowList().add(rowDTO);
                    List<ClassesFormShiftDTO> shiftList = IntStream.range(1, days+1)
                            .mapToObj(e -> this.buildShift(map.get(e), e))
                            .peek(e -> {
                                e.setUserId(classesFormUser.getUserId());
                                e.setUserName(classesFormUser.getUserName());
                                e.setUserPinyin(classesFormUser.getUserPinyin());
                                e.setRankId(rowDTO.getRankId());
                                e.setRankName(rowDTO.getRankName());
                                e.setRankPinyin(rowDTO.getRankPinyin());
                            })
                            .collect(Collectors.toList());
                    rowDTO.setShiftList(shiftList);

                } else if (rankMap.containsKey(firstCol)) {
                    classesFormRowDto = new ClassesFormRowDTO();
                    ClassesFormRankDTO classesFormRankDTO = rankMap.get(firstCol);
                    classesFormRowDto.setRankId(classesFormRankDTO.getRankId());
                    classesFormRowDto.setRankName(classesFormRankDTO.getRankName());
                    classesFormRowDto.setRankPinyin(classesFormRankDTO.getRankPinyin());
                } else if (userPinyinMap.containsKey(firstCol)) {
                    // 有拼音，暂不处理
                } else {
                    throw new IllegalArgumentException("未找到该岗位或用户：" + firstCol);
                }
            }

            saveData(factory);
        }

    }

    private ClassesFormShiftDTO buildShift(String classesName, int day) {
        ClassesClassifyItem classesClassifyItem = classesItemMap.get(StrUtil.trim(classesName));
        ClassesFormShiftDTO shiftDTO = new ClassesFormShiftDTO();
        if (classesClassifyItem == null) {
            return shiftDTO;
        }
        shiftDTO.setClassesId(classesClassifyItem.getClassesId());
        shiftDTO.setClassesItemId(classesClassifyItem.getId());
        shiftDTO.setClassesItemName(classesClassifyItem.getName());
        // 获取月份
        Date shiftYm = classesFormDTO.getShiftTime();
        // 计算日期
        Calendar instance = Calendar.getInstance();
        instance.set(DateUtil.year(shiftYm), DateUtil.month(shiftYm), day);
        shiftDTO.setShiftDate(instance.getTime());
        shiftDTO.setShiftWeekday(DateUtil.dayOfWeekEnum(instance.getTime()).toChinese(""));
        if (!"0".equals(classesClassifyItem.getTabs())) {
            return shiftDTO;
        }
        // 开始时间
        DateTime startTime = DateUtil.parse(classesClassifyItem.getStartTime(), "HH:mm");
        instance.set(Calendar.HOUR_OF_DAY, DateUtil.hour(startTime, true));
        instance.set(Calendar.MINUTE,  DateUtil.minute(startTime));
        shiftDTO.setClassesStartTime(instance.getTime());
        // 结束时间
        if ("24:00".equals(classesClassifyItem.getEndTime())) {
            instance.add(Calendar.DATE, 1);
            instance.set(Calendar.HOUR_OF_DAY, 0);
            instance.set(Calendar.MINUTE,  0);
            shiftDTO.setClassesEndTime(instance.getTime());
            instance.add(Calendar.DATE, -1);
        } else {
            DateTime endTime = DateUtil.parse(classesClassifyItem.getEndTime(), "HH:mm");
            instance.set(Calendar.HOUR_OF_DAY, DateUtil.hour(endTime, true));
            instance.set(Calendar.MINUTE,  DateUtil.minute(endTime));
            shiftDTO.setClassesEndTime(instance.getTime());
        }

        // 时长
        shiftDTO.setDuration(classesClassifyItem.getDuration());

        // 加班开始时间
        if (classesClassifyItem.getOverStartTime() != null) {
            DateTime overStartTime = DateUtil.parse(classesClassifyItem.getOverStartTime(), "HH:mm");
            instance.set(Calendar.HOUR_OF_DAY, DateUtil.hour(overStartTime, true));
            instance.set(Calendar.MINUTE,  DateUtil.minute(overStartTime));
            shiftDTO.setOverStartTime(instance.getTime());
        }

        // 加班结束时间
        if (classesClassifyItem.getOverEndTime() != null) {
            if ("24:00".equals(classesClassifyItem.getOverEndTime())) {
                instance.add(Calendar.DATE, 1);
                instance.set(Calendar.HOUR_OF_DAY, 0);
                instance.set(Calendar.MINUTE,  0);
                shiftDTO.setOverEndTime(instance.getTime());
                instance.add(Calendar.DATE, -1);
            } else {
                DateTime overEndTime = DateUtil.parse(classesClassifyItem.getOverEndTime(), "HH:mm");
                instance.set(Calendar.HOUR_OF_DAY, DateUtil.hour(overEndTime, true));
                instance.set(Calendar.MINUTE,  DateUtil.minute(overEndTime));
                shiftDTO.setOverEndTime(instance.getTime());
            }
        }

        // 加班时长
        shiftDTO.setOverDuration(classesClassifyItem.getOverDuration());
        return shiftDTO;
    }

    /**
     * 加上存储数据库
     */
    private void saveData(SessionFactory factory) {
        classesFormService.saveDto(factory, classesFormDTO);
    }

}
